# knowledge/query/kb_query_engine.py

import logging
import re
import json
import chromadb
import os
from typing import Dict, List, Optional, Any, Tuple
from llama_index.core import VectorStoreIndex
from llama_index.core.schema import NodeWithScore
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.response_synthesizers import get_response_synthesizer
from llama_index.core.llms import LLM
from knowledge.database.db_manager import DatabaseManager
from knowledge.database.db_schema_manager import DBSchemaManager
from knowledge.util.tools import logging_helper



class KBQueryEngine:
    """增强版查询引擎 - 支持数据库查询和知识库查询的智能融合"""
    
    def __init__(self, index: VectorStoreIndex, db_manager: DatabaseManager = None, schema_manager: DBSchemaManager = None, llm: LLM = None, verbose: bool = False):
        self.logger = logging.getLogger("KnowledgeBase.query_engine")
        self.index = index
        self.db_manager = db_manager
        self.schema_manager = schema_manager
        self.llm = llm
        self.verbose = verbose
        
        # 创建检索器
        self.retriever = VectorIndexRetriever(
            index=index,
            similarity_top_k=5,
        )
        
        # 创建响应合成器
        self.response_synthesizer = get_response_synthesizer()
        
        # 创建查询引擎
        self.query_engine = RetrieverQueryEngine(
            retriever=self.retriever,
            response_synthesizer=self.response_synthesizer
        )
        
        # 预定义数据库和知识库的描述摘要
        self.database_summary = self._get_database_summary()
        self.knowledge_base_summary = self._get_knowledge_base_summary()
        
        logging_helper.info_if_verbose(self.logger,self.verbose,"智能融合查询引擎初始化完成")
        if db_manager:
            logging_helper.info_if_verbose(self.logger,self.verbose,"✅ 数据库查询功能已启用")
        if schema_manager:
            logging_helper.info_if_verbose(self.logger,self.verbose,"✅ Schema管理器已启用")
        if llm:
            logging_helper.info_if_verbose(self.logger,self.verbose,"✅ LLM智能问题分解功能已启用")
    
    def integrated_query(self, query_text: str, show_details: bool = False) -> Dict:
        """
        智能融合查询：结合数据库查询和知识库查询
        
        Args:
            query_text: 用户查询文本
            show_details: 是否显示详细信息
            
        Returns:
            dict: 包含最终答案和查询过程的完整结果
        """
        self.logger.info(f"🧠 开始智能融合查询: {query_text}")
        
        # 1. 分析用户问题
        self.logger.info("📋 智能融合步骤1: 分析用户问题...")
        query_analysis = self.analyze_user_query(query_text)
        db_query = query_analysis["db_query"]
        kb_query = query_analysis["kb_query"]
        
        self.logger.info(f"问题分析结果: 数据库查询='{db_query}', 知识库查询='{kb_query}'")
        
        db_results = None
        kb_results = None
        db_answer = ""
        kb_answer = ""
        final_answer = ""
        
        # 2. 执行数据库查询（如果存在）- 复用query_with_database方法
        if db_query and self.db_manager:
            self.logger.info("🗃️  智能融合步骤2: 执行数据库查询...")
            try:
                # 复用query_with_database方法执行数据库查询
                db_results = self.query_with_database(db_query, show_details=show_details)
                
                # 获取数据库查询的最终答案
                db_answer = db_results.get("answer", "") if db_results else ""
                if db_answer:
                    self.logger.info(f"📊 数据库查询结果: {db_answer}")
                else:
                    self.logger.info("📊 数据库查询无结果")
                
                # 3. 基于数据库结果重新评估是否需要知识库查询
                self.logger.info("🔄 智能融合步骤3: 基于数据库结果重新评估知识库查询...")
                enhanced_kb_query = self._reevaluate_kb_query_after_db(
                    kb_query, db_answer, query_text, original_kb_query=kb_query
                )
                
                if enhanced_kb_query:
                    kb_query = enhanced_kb_query
                    self.logger.info(f"重新评估后的知识库查询: {kb_query}")
                else:
                    self.logger.info("重新评估后仍无需知识库查询")
                    
            except Exception as e:
                self.logger.error(f"数据库查询失败: {e}")
                db_results = {"error": str(e), "data": []}
        else:
            self.logger.info("⏭️  跳过数据库查询")
        
        # 4. 执行知识库查询（如果存在或重新评估后需要）- 复用query方法
        if kb_query:
            self.logger.info("📚 智能融合步骤4: 执行知识库查询...")
            try:
                # 复用query方法执行知识库查询
                kb_results = self.query(kb_query, show_details=False)
                
                # 获取知识库查询的完整答案
                kb_answer = kb_results.get("answer", "") if kb_results else ""
                if kb_answer:
                    # 记录完整的知识库答案
                    self.logger.info(f"📖 知识库查询结果 (完整内容，长度: {len(kb_answer)}字符):")
                    self.logger.info(f"  内容: {kb_answer}")
                else:
                    self.logger.info("📖 知识库查询无结果")
                
            except Exception as e:
                self.logger.error(f"知识库查询失败: {e}")
                kb_results = {"error": str(e), "answer": ""}
        else:
            self.logger.info("⏭️  跳过知识库查询")
        
        # 5. 生成最终答案 - 直接传递最终答案而不是复杂对象
        self.logger.info("🤖 智能融合步骤5: 生成最终答案...")
        final_answer = self._generate_integrated_answer(
            query_text, db_query, db_answer, kb_query, kb_answer
        )
        
        # 记录最终答案
        self.logger.info(f"💡 最终答案 (长度: {len(final_answer)}字符):")
        self.logger.info(f"  内容: {final_answer}")
        
        # 6. 构建返回结果
        result = {
            "query": query_text,
            "answer": final_answer,
            "source": "integrated",
            "analysis": query_analysis,
            "process_details": {
                "database": {
                    "query": db_query,
                    "answer": db_answer,
                    "results": db_results.get("metadata", {}).get("raw_results", []) if db_results else [],
                    "result_count": db_results.get("metadata", {}).get("result_count", 0) if db_results else 0,
                    "sql_used": db_results.get("metadata", {}).get("sql_query", "") if db_results else ""
                } if db_results else None,
                "knowledge_base": {
                    "query": kb_query,
                    "answer": kb_answer,
                    "source_count": kb_results.get("metadata", {}).get("node_count", 0) if kb_results else 0
                } if kb_results else None
            }
        }
        
        if show_details:
            result["debug_info"] = {
                "db_raw_results": db_results,
                "kb_raw_results": kb_results
            }
        
        self.logger.info("✅ 智能融合查询完成")
        return result

    def _generate_integrated_answer(self, original_query: str, db_query: Optional[str], 
                            db_answer: str, kb_query: Optional[str], 
                            kb_answer: str) -> str:
        """生成融合的最终答案 - 直接使用数据库和知识库的最终答案"""
        if not self.llm:
            return self._generate_fallback_answer_from_text(db_answer, kb_answer)
        
        try:
            prompt = self._build_integrated_answer_prompt(
                original_query, db_query, db_answer, kb_query, kb_answer
            )
            
            # 记录发送给LLM的提示词（前500字符）
            logging_helper.info_if_verbose(self.logger,self.verbose,f"📤 发送给LLM的提示词预览 (长度: {len(prompt)}字符):")
            
            prompt_preview = prompt[:500] + "..." if len(prompt) > 500 else prompt
            logging_helper.info_if_verbose(self.logger,self.verbose,f"  内容: {prompt_preview}")
            
            # 移除token限制
            if hasattr(self.llm, 'max_tokens'):
                original_max_tokens = self.llm.max_tokens
                self.llm.max_tokens = 4000
            else:
                original_max_tokens = None
            
            response = self.llm.complete(prompt)
            final_answer = response.text.strip()
            
            # 恢复token设置
            if hasattr(self.llm, 'max_tokens') and original_max_tokens is not None:
                self.llm.max_tokens = original_max_tokens
            
            return final_answer
            
        except Exception as e:
            self.logger.error(f"融合答案生成失败: {e}")
            return self._generate_fallback_answer_from_text(db_answer, kb_answer)

    def _build_integrated_answer_prompt(self, original_query: str, db_query: Optional[str],
                                    db_answer: str, kb_query: Optional[str],
                                    kb_answer: str) -> str:
        """构建融合答案生成的提示词"""
        
        # 准备数据库结果信息
        db_info = f"数据库查询结果:\n{db_answer}" if db_answer else "数据库查询：无相关数据"
        
        # 准备知识库结果信息
        kb_info = f"知识库查询结果:\n{kb_answer}" if kb_answer else "知识库查询：无相关信息"
        
        prompt = f"""请基于以下查询结果，为用户问题生成一个完整、准确、自然的回答。

        用户原始问题: {original_query}

        查询过程:
        📊 数据库查询: {db_query or "未执行"}
        {db_info}

        📖 知识库查询: {kb_query or "未执行"}
        {kb_info}

        请生成最终答案要求:
        1. 直接、完整地回答用户问题
        2. 有机整合数据库数据和知识库信息
        3. 如果数据库和知识库都有相关信息，要综合两者的信息
        4. 语言自然流畅，避免技术术语
        5. 如果某些方面没有相关信息，如实说明
        6. 确保答案基于提供的数据和知识，不要编造信息
        7. 用中文回答，保持专业和友好

        请直接给出完整详细的最终答案："""

        return prompt

    def _generate_fallback_answer_from_text(self, db_answer: str, kb_answer: str) -> str:
        """生成备选答案（当LLM不可用时）- 基于文本答案"""
        parts = []
        
        if db_answer:
            parts.append(f"数据库查询结果：{db_answer}")
            
        if kb_answer:
            parts.append(f"相关知识库信息：{kb_answer}")
        
        if not parts:
            return "抱歉，没有找到相关信息。"
        
        return " ".join(parts)
    
    def _get_database_summary(self) -> str:
        """获取数据库结构摘要"""
        return """数据库包含以下核心业务表：
        - employees(员工信息表): 存储公司员工基本信息，包括联系方式、部门和职位
        - products(产品信息表): 存储公司产品和服务信息，包括产品描述和负责人
        - pipline(商机表): 记录销售机会和潜在业务的全过程管理，跟踪从跟进到赢单/丢单的完整生命周期
        - projects(项目表): 记录已签约项目的执行情况，包括合同金额、项目经理和项目状态
        - projects_products(项目产品关联表): 记录项目中销售的具体产品信息，包括销售金额和实施成本
        
        这些表涵盖了企业的人员、产品、商机、项目等核心业务数据。"""
    
    def _get_knowledge_base_summary(self) -> str:
        """获取知识库内容摘要"""
        return """企业知识库主要包含以下类型的文档：
        - 公司制度与政策：员工手册、考勤制度、报销政策等
        - 业务流程文档：项目管理办法、销售流程、客户服务规范等
        - 产品技术文档：产品说明书、技术白皮书、API文档等
        - 培训材料：新员工培训、技能提升课程等
        - 会议纪要：重要决策和讨论记录
        - 最佳实践：各部门的工作经验和成功案例
        
        知识库主要关注企业的规章制度、业务流程、产品信息和内部管理文档。"""
    
    def analyze_user_query(self, query_text: str) -> Dict[str, Optional[str]]:
        """
        使用LLM分析用户问题，分解为数据库查询和知识库查询两部分
        
        Returns:
            dict: 包含db_query和kb_query的字典
        """
        if not self.llm:
            self.logger.warning("LLM未配置，使用默认问题分析")
            return self._default_query_analysis(query_text)
        
        try:
            prompt = self._build_query_analysis_prompt(query_text)
            response = self.llm.complete(prompt)
            analysis_result = response.text.strip()
            
            return self._parse_analysis_result(analysis_result, query_text)
            
        except Exception as e:
            self.logger.error(f"问题分析失败: {e}")
            return self._default_query_analysis(query_text)
    
    def _build_query_analysis_prompt(self, query_text: str) -> str:
        """构建问题分析提示词"""
        prompt = f"""请分析以下用户问题，将其分解为最多两个部分：

        用户问题: "{query_text}"

        系统能力说明:
        1. 数据库查询能力: {self.database_summary}
        2. 知识库查询能力: {self.knowledge_base_summary}

        分析要求:
        1. 如果问题涉及员工、产品、商机、项目、金额、数量等结构化数据，提取为数据库查询部分
        2. 如果问题涉及公司制度、业务流程、政策规定、技术文档等非结构化知识，提取为知识库查询部分
        3. 一个问题可能同时包含两部分，也可能只有一部分
        4. 如果问题无法匹配任何部分，则标记为无法处理

        请按以下JSON格式返回分析结果：
        {{
            "db_query": "需要数据库查询的具体问题内容，如无则为null",
            "kb_query": "需要知识库查询的具体问题内容，如无则为null",
            "reasoning": "分析理由"
        }}

        请只返回JSON格式的结果，不要有其他内容。"""

        return prompt
    
    def _parse_analysis_result(self, analysis_result: str, original_query: str) -> Dict[str, Optional[str]]:
        """解析LLM的分析结果"""
        try:
            # 尝试提取JSON部分
            json_match = re.search(r'\{.*\}', analysis_result, re.DOTALL)
            if json_match:
                result = json.loads(json_match.group())
                
                # 验证结果格式
                if "db_query" in result and "kb_query" in result:
                    # 处理null值
                    db_query = result["db_query"] if result["db_query"] and result["db_query"].lower() != "null" else None
                    kb_query = result["kb_query"] if result["kb_query"] and result["kb_query"].lower() != "null" else None
                    
                    logging_helper.info_if_verbose(self.logger,self.verbose,f"问题分析结果: db_query={db_query}, kb_query={kb_query}")
                    if "reasoning" in result:
                        logging_helper.info_if_verbose(self.logger,self.verbose,f"分析理由: {result['reasoning']}")
                    
                    return {
                        "db_query": db_query,
                        "kb_query": kb_query
                    }
        
        except Exception as e:
            self.logger.warning(f"解析分析结果失败: {e}")
        
        # 解析失败时使用默认分析
        return self._default_query_analysis(original_query)
    
    def _default_query_analysis(self, query_text: str) -> Dict[str, Optional[str]]:
        """默认问题分析逻辑"""
        query_lower = query_text.lower()
        
        # 数据库查询关键词
        db_keywords = [
            '员工', '产品', '商机', '项目', '金额', '数量', '统计', '总计', '汇总',
            'employee', 'product', 'pipline', 'project', 'amount', 'count', 'sum'
        ]
        
        # 知识库查询关键词  
        kb_keywords = [
            '制度', '政策', '流程', '规范', '手册', '文档', '说明', '规定', '办法',
            'policy', 'process', 'manual', 'document', 'specification'
        ]
        
        has_db_query = any(keyword in query_lower for keyword in db_keywords)
        has_kb_query = any(keyword in query_lower for keyword in kb_keywords)
        
        # 如果同时包含两类关键词，进行简单分割
        if has_db_query and has_kb_query:
            # 简单逻辑：包含数字和业务术语的倾向于数据库查询
            if any(word in query_lower for word in ['多少', '几个', '金额', '数量']):
                return {
                    "db_query": query_text,
                    "kb_query": query_text
                }
            else:
                return {
                    "db_query": None,
                    "kb_query": query_text
                }
        elif has_db_query:
            return {
                "db_query": query_text,
                "kb_query": None
            }
        else:
            return {
                "db_query": None,
                "kb_query": query_text
            }

    def _reevaluate_kb_query_after_db(self, kb_query: Optional[str], db_answer: str, 
                            original_query: str, original_kb_query: Optional[str]) -> Optional[str]:
        """
        基于数据库结果重新评估是否需要知识库查询
        
        Args:
            kb_query: 当前知识库查询（可能为None）
            db_answer: 数据库查询的最终答案
            original_query: 原始用户查询
            original_kb_query: 原始知识库查询（用于比较）
            
        Returns:
            Optional[str]: 重新评估后的知识库查询，如果不需要则为None
        """
        if not self.llm:
            self.logger.warning("LLM未配置，无法重新评估知识库查询")
            return kb_query
        
        # 如果数据库查询失败或无结果，保持原样
        if not db_answer or db_answer.strip() == "":
            return kb_query
        
        try:
            prompt = self._build_reevaluation_prompt(kb_query, db_answer, original_query, original_kb_query)
            
            # 在调用LLM之前，记录完整的提示词
            logging_helper.info_if_verbose(self.logger,self.verbose,"📤 重新评估知识库查询问题-发送给LLM的完整提示词:")
            
            logging_helper.info_if_verbose(self.logger,self.verbose,"=" * 80)
            logging_helper.info_if_verbose(self.logger,self.verbose,prompt)
            logging_helper.info_if_verbose(self.logger,self.verbose,"=" * 80)
            
            response = self.llm.complete(prompt)
            reevaluated_query = response.text.strip()
            
            # 记录LLM的响应
            logging_helper.info_if_verbose(self.logger,self.verbose,f"📥 重新评估知识库查询问题-LLM响应: {reevaluated_query}")
            
            # 解析LLM的响应
            if reevaluated_query.lower() in ["null", "none", "无需查询", "无", ""]:
                return None
            elif reevaluated_query and len(reevaluated_query) > 5:
                return reevaluated_query
            else:
                return kb_query
                
        except Exception as e:
            self.logger.warning(f"重新评估知识库查询失败: {e}")
            return kb_query

    def _build_reevaluation_prompt(self, kb_query: Optional[str], db_answer: str, 
                            original_query: str, original_kb_query: Optional[str]) -> str:
        """构建重新评估知识库查询的提示词"""
        
        prompt = f"""你是一个智能查询分析助手。请基于数据库查询结果，重新评估是否需要知识库查询，以及如何优化知识库查询问题。

        用户原始问题: "{original_query}"

        数据库查询结果:
        {db_answer}

        当前知识库查询状态: {"'" + kb_query + "'" if kb_query else "无"}
        原始知识库查询: {"'" + original_kb_query + "'" if original_kb_query else "无"}

        请仔细分析以下内容：

        1. 数据库查询结果是否已经完整回答了用户问题？
        2. 用户问题中是否还有需要从知识库获取的补充信息？
        3. 如果需要知识库查询，应该查询什么具体内容？

        评估规则：
        - 如果数据库结果已经完整、准确地回答了用户问题，不需要额外信息，返回 "null"
        - 如果用户问题涉及制度、政策、流程、规范、文档、说明、指南、手册等非结构化知识，需要知识库查询
        - 如果数据库结果提到了具体的产品、项目、人员、部门等实体，需要查询相关的文档资料
        - 基于数据库结果中的所有相关信息来优化知识库查询问题，不要遗漏重要实体

        具体判断标准：
        ✓ 需要知识库查询的情况：
        - 查询产品/项目的详细说明文档、技术规格
        - 查询人员/部门的职责说明、工作规范
        - 查询相关业务流程、操作指南
        - 查询政策制度、管理办法
        - 查询培训材料、最佳实践

        ✓ 不需要知识库查询的情况：
        - 纯粹的统计问题（数量、金额等）
        - 简单的事实查询（姓名、联系方式等）
        - 数据库结果已经提供了所有必要信息

        优化知识库查询的示例：
        示例1:
        数据库结果包含产品"企业级知识库引擎"和"AI问答机器人"
        优化后: "企业级知识库引擎和AI问答机器人的产品说明文档、技术规格和使用指南"

        请基于上述分析，返回优化后的知识库查询问题，如果不需要则返回 "null"：

        优化后的知识库查询:"""

        return prompt
    
    def _generate_fallback_answer(self, db_results: Optional[Dict], kb_results: Optional[Dict]) -> str:
        """生成备选答案（当LLM不可用时）"""
        parts = []
        
        if db_results and db_results.get("answer"):
            parts.append(f"数据库查询结果：{db_results['answer']}")
            
        if kb_results and kb_results.get("answer"):
            kb_answer = kb_results["answer"]
            # 截取知识库回答的前200字符
            kb_preview = kb_answer[:200] + "..." if len(kb_answer) > 200 else kb_answer
            parts.append(f"相关知识库信息：{kb_preview}")
        
        if not parts:
            return "抱歉，没有找到相关信息。"
        
        return " ".join(parts)
    
    def query_with_database(self, query_text: str, show_details: bool = True) -> Dict:
        """执行数据库查询（不涉及知识库）"""
        logging_helper.info_if_verbose(self.logger,show_details,f"开始数据库查询: {query_text}")
        
        if not self.db_manager:
            self.logger.warning("❌ 数据库管理器未配置")
            return {
                "query": query_text,
                "answer": "数据库查询功能未配置",
                "source": "database",
                "error": "数据库管理器未配置"
            }
        
        try:
            # 1. 直接从ChromaDB获取Schema信息
            logging_helper.info_if_verbose(self.logger,show_details,"📋 数据库查询步骤1: 从ChromaDB获取数据库Schema信息...")
            schema_results = self._query_schema_directly(query_text, n_results=5)
            
            if "error" in schema_results:
                self.logger.warning(f"Schema查询失败: {schema_results['error']}")
                # 继续使用启发式方法
            
            if show_details:
                documents = schema_results.get('results', {}).get('documents', [[]])[0]
                logging_helper.info_if_verbose(self.logger,show_details,f"📊 Schema查询结果: {len(documents)} 个相关表")
                for i, doc in enumerate(documents):
                    metadata = schema_results.get('results', {}).get('metadatas', [[]])[0][i] if schema_results.get('results', {}).get('metadatas') and i < len(schema_results.get('results', {}).get('metadatas', [[]])[0]) else {}
                    similarity = 1 - schema_results.get('results', {}).get('distances', [[]])[0][i] if schema_results.get('results', {}).get('distances') and i < len(schema_results.get('results', {}).get('distances', [[]])[0]) else 0
                    logging_helper.info_if_verbose(self.logger,show_details,f"  📄 相关表 {i+1}: {metadata.get('table_name', '未知')} (相似度: {similarity:.3f})")
            
            # 2. 基于Schema信息生成并执行SQL查询（带重试机制）
            logging_helper.info_if_verbose(self.logger,show_details,"🔧 数据库查询步骤2: 生成并执行SQL查询语句...")
            sql_result = self._generate_and_execute_sql_with_retry(query_text, schema_results, max_retries=3)
            
            sql_query = sql_result["sql_query"]
            db_results = sql_result["db_results"]
            retry_count = sql_result["retry_count"]
            
            logging_helper.info_if_verbose(self.logger,show_details,f"📝 最终SQL: {sql_query}")    
            logging_helper.info_if_verbose(self.logger,show_details,f"🔄 重试次数: {retry_count}")
            logging_helper.info_if_verbose(self.logger,show_details,f"📊 SQL查询结果: {len(db_results)} 条记录")
            
            # 详细记录查询结果
            if db_results:
                logging_helper.info_if_verbose(self.logger,show_details,"🔍 查询结果详情:")
                for i, row in enumerate(db_results):
                    logging_helper.info_if_verbose(self.logger,show_details,f"  记录 {i+1}: {dict(row)}")
            
            # 3. 使用LLM生成最终答案 - 去掉token限制
            logging_helper.info_if_verbose(self.logger,show_details,"🤖 数据库查询步骤3: 使用LLM生成完整答案...")
            final_answer = self._generate_database_answer_with_llm(query_text, sql_query, db_results)
            logging_helper.info_if_verbose(self.logger,show_details,f"💡 最终答案长度: {len(final_answer)} 字符")
            logging_helper.info_if_verbose(self.logger,show_details,f"📄 最终答案内容: {final_answer}")
            
            # 4. 如果数据库查询无结果或LLM生成失败，返回简单结果
            if not final_answer or final_answer.strip() == "":
                logging_helper.info_if_verbose(self.logger,show_details,"📭 数据库查询结果处理失败，返回简单结果")
                final_answer = self._generate_simple_database_answer(db_results)
            
            result = {
                "query": query_text,
                "answer": final_answer,
                "source": "database",
                "metadata": {
                    "sql_query": sql_query,
                    "result_count": len(db_results),
                    "retry_count": retry_count,
                    "raw_results": db_results[:10] if show_details else [],
                    "schema_used": [
                        {
                            "table_name": schema_results.get('results', {}).get('metadatas', [[]])[0][i].get('table_name', '未知'),
                            "similarity": 1 - schema_results.get('results', {}).get('distances', [[]])[0][i] if schema_results.get('results', {}).get('distances') and i < len(schema_results.get('results', {}).get('distances', [[]])[0]) else 0
                        }
                        for i in range(len(schema_results.get('results', {}).get('documents', [[]])[0]))
                    ] if schema_results.get('results', {}).get('documents') else []
                }
            }
            
            logging_helper.info_if_verbose(self.logger,show_details,"✅ 数据库查询完成")
            return result
            
        except Exception as e:
            self.logger.error(f"❌ 数据库查询失败: {e}")
            return {
                "query": query_text,
                "answer": f"数据库查询失败: {str(e)}",
                "source": "database",
                "error": str(e)
            }

    def _generate_database_answer_with_llm(self, query_text: str, sql_query: str, db_results: List[Dict]) -> str:
        """使用LLM基于数据库查询结果生成完整答案（无token限制）"""
        if not self.llm:
            self.logger.warning("❌ LLM未配置，无法生成自然语言答案")
            return self._generate_simple_database_answer(db_results)
        
        try:
            # 构建提示词
            prompt = self._build_database_answer_prompt(query_text, sql_query, db_results)
            
            # 记录发送给LLM的提示词（前500字符）
            logging_helper.info_if_verbose(self.logger,self.verbose,f"📤 发送给LLM的提示词预览 (长度: {len(prompt)}字符):")
            
            prompt_preview = prompt[:500] + "..." if len(prompt) > 500 else prompt
            logging_helper.info_if_verbose(self.logger,self.verbose,f"  内容: {prompt_preview}")
            
            # 移除token限制，让LLM生成完整答案
            if hasattr(self.llm, 'max_tokens'):
                # 设置为较大的值或不设置限制
                original_max_tokens = self.llm.max_tokens
                self.llm.max_tokens = 4000  # 设置较大的token限制
            else:
                original_max_tokens = None
            
            # 使用LLM生成答案
            response = self.llm.complete(prompt)
            final_answer = response.text.strip()
            
            # 恢复原来的token设置（如果有）
            if hasattr(self.llm, 'max_tokens') and original_max_tokens is not None:
                self.llm.max_tokens = original_max_tokens
            
            return final_answer
            
        except Exception as e:
            self.logger.error(f"❌ LLM生成数据库答案失败: {e}")
            return self._generate_simple_database_answer(db_results)

    def _build_database_answer_prompt(self, query_text: str, sql_query: str, db_results: List[Dict]) -> str:
        """构建数据库答案生成的提示词"""
        
        # 格式化查询结果
        if db_results:
            results_str = json.dumps(db_results, ensure_ascii=False, indent=2)
            results_info = f"查询结果:\n{results_str}"
        else:
            results_info = "查询结果: 无数据"
        
        prompt = f"""你是一个专业的数据分析助手。请基于以下数据库查询结果，用自然语言完整、详细地回答用户的问题：

        用户问题: {query_text}

        执行的SQL查询: {sql_query}

        {results_info}

        请根据查询结果，生成一个清晰、准确、完整的回答：
        1. 直接回应用户的问题，提供完整的信息
        2. 如果查询结果为空，如实告知用户
        3. 如果查询到数据，用用户能理解的方式完整呈现所有相关信息
        4. 保持语言简洁明了，但不要遗漏重要信息
        5. 直接给出完整答案，不要有"根据查询结果"等前缀
        6. 不要截断答案，确保回答完整详细

        请直接给出完整详细的最终答案："""
        
        return prompt

    def _generate_simple_database_answer(self, db_results: List[Dict]) -> str:
        """生成简单的数据库答案（当LLM不可用时）"""
        if not db_results:
            return "没有找到相关数据。"
        
        answer_parts = []
        answer_parts.append(f"共找到 {len(db_results)} 条记录：")
        
        for i, record in enumerate(db_results[:10], 1):  # 最多显示10条记录
            record_str = ", ".join([f"{k}: {v}" for k, v in record.items()])
            answer_parts.append(f"{i}. {record_str}")
        
        if len(db_results) > 10:
            answer_parts.append(f"... 还有 {len(db_results) - 10} 条记录")
        
        return "\n".join(answer_parts)

    def _regenerate_sql_with_error(self, query_text: str, relevant_schemas: List[Dict], 
                              last_sql: str, error: str, retry_count: int) -> str:
        """基于错误信息重新生成SQL"""
        if not self.llm:
            self.logger.warning("❌ LLM未配置，无法重新生成SQL")
            return self._generate_heuristic_sql(query_text, relevant_schemas)
        
        try:
            prompt = self._build_retry_sql_prompt(query_text, relevant_schemas, last_sql, error, retry_count)
            response = self.llm.complete(prompt)
            sql_query = response.text.strip()
            
            # 清理SQL语句
            sql_query = self._extract_sql_from_response(sql_query)
            logging_helper.info_if_verbose(self.logger,self.verbose,f"🔄 重新生成的SQL: {sql_query}")
            return sql_query
            
        except Exception as e:
            self.logger.warning(f"❌ 重新生成SQL失败: {e}")
            return self._generate_heuristic_sql(query_text, relevant_schemas)
    
    def _query_schema_directly(self, query_text: str, n_results: int = 5) -> Dict:
        """直接从ChromaDB查询Schema信息"""
        try:
            # 初始化ChromaDB客户端
            settings = chromadb.config.Settings(anonymized_telemetry=False)
            
            # 获取schema存储路径（与DBSchemaManager相同的路径）
            current_dir = os.path.dirname(os.path.abspath(__file__))
            kb_root = os.path.dirname(os.path.dirname(current_dir))
            chroma_db_path = os.path.join(kb_root, "enterprise_knowledge")
            
            chroma_client = chromadb.PersistentClient(
                path=chroma_db_path,
                settings=settings
            )
            
            # 获取Schema集合
            collection_name = "project_sys_schema"
            try:
                collection = chroma_client.get_collection(collection_name)
            except Exception as e:
                self.logger.error(f"获取Schema集合失败: {e}")
                return {"error": f"Schema集合 {collection_name} 不存在"}
            
            # 使用与向量化时相同的嵌入模型
            from llama_index.core import Settings
            if hasattr(Settings, 'embed_model') and Settings.embed_model:
                logging_helper.info_if_verbose(self.logger,self.verbose,f"使用嵌入模型查询Schema: {Settings.embed_model.model_name}")
                query_embedding = Settings.embed_model.get_query_embedding(query_text)
                
                # 执行带嵌入向量的查询
                results = collection.query(
                    query_embeddings=[query_embedding],
                    n_results=n_results
                )
                embedding_model_used = Settings.embed_model.model_name
            else:
                # 回退到文本查询
                self.logger.warning("嵌入模型未配置，使用文本查询")
                results = collection.query(
                    query_texts=[query_text],
                    n_results=n_results
                )
                embedding_model_used = "text_query_fallback"
            
            return {
                "query": query_text,
                "results": results,
                "collection": collection_name,
                "embedding_model": embedding_model_used,
                "total_results": len(results.get('documents', [])[0]) if results.get('documents') else 0
            }
            
        except Exception as e:
            self.logger.error(f"直接查询Schema失败: {e}")
            return {"error": str(e)}
    
    def _build_retry_sql_prompt(self, query_text: str, relevant_schemas: List[Dict], 
                           last_sql: str, error: str, retry_count: int) -> str:
        """构建重试SQL生成的提示词"""
        
        # 构建相关表结构
        detailed_schemas = "\n相关表的详细结构:\n"
        for schema in relevant_schemas:
            detailed_schemas += f"\n表: {schema['table_name']}\n{schema['content']}\n"
        
        prompt = f"""之前的SQL执行失败，请基于错误信息重新生成SQLite兼容的SQL语句。

        原始查询: "{query_text}"

        相关表结构:
        {detailed_schemas}

        之前生成的SQL: {last_sql}

        执行错误: {error}

        重试次数: {retry_count}

        请分析错误原因，生成一个修正后的SQLite兼容SQL语句。只返回SQL语句，不要有其他解释。

        修正后的SQL查询:"""
        
        return prompt
    
    def _extract_relevant_schemas(self, schema_results: Dict) -> List[Dict]:
        """提取相关表结构信息"""
        relevant_schemas = []
        documents = schema_results.get('results', {}).get('documents', [[]])[0]
        metadatas = schema_results.get('results', {}).get('metadatas', [[]])[0]
        
        for i, doc in enumerate(documents):
            if i < len(metadatas):
                table_name = metadatas[i].get('table_name')
                if table_name and table_name not in ['global_info', 'relationships']:
                    relevant_schemas.append({
                        'table_name': table_name,
                        'content': doc
                    })
        
        return relevant_schemas

    def _generate_and_execute_sql_with_retry(self, query_text: str, schema_results: Dict, max_retries: int = 3) -> Dict:
        """生成并执行SQL查询（带重试机制）"""
        relevant_schemas = self._extract_relevant_schemas(schema_results)
        
        # 初始SQL生成
        sql_query = self._generate_sql_with_llm(query_text, relevant_schemas)
        logging_helper.info_if_verbose(self.logger,self.verbose,f"📝 初始SQL: {sql_query}")
        
        retry_count = 0
        last_error = ""
        
        while retry_count <= max_retries:
            try:
                # 执行SQL查询
                db_results = self.db_manager.execute_query(sql_query)
                
                # 如果查询成功，返回结果
                return {
                    "sql_query": sql_query,
                    "db_results": db_results,
                    "retry_count": retry_count
                }
                
            except Exception as e:
                last_error = str(e)
                retry_count += 1
                self.logger.warning(f"🔄 SQL执行失败 (重试 {retry_count}/{max_retries}): {last_error}")
                
                if retry_count > max_retries:
                    break
                
                # 重新生成SQL
                sql_query = self._regenerate_sql_with_error(query_text, relevant_schemas, sql_query, last_error, retry_count)
        
        # 所有重试都失败，使用启发式方法
        self.logger.warning("💡 所有重试失败，使用启发式SQL生成")
        fallback_sql = self._generate_heuristic_sql(query_text, relevant_schemas)
        
        try:
            db_results = self.db_manager.execute_query(fallback_sql)
            return {
                "sql_query": fallback_sql,
                "db_results": db_results,
                "retry_count": retry_count
            }
        except Exception as e:
            self.logger.error(f"❌ 启发式SQL也失败: {e}")
            return {
                "sql_query": fallback_sql,
                "db_results": [],
                "retry_count": retry_count,
                "error": f"所有SQL生成方法都失败: {last_error}"
            }

    def _generate_sql_with_llm(self, query_text: str, relevant_schemas: List[Dict]) -> str:
        """使用LLM生成SQL查询语句"""
        if not self.llm:
            self.logger.warning("❌ LLM未配置，使用启发式SQL生成")
            return self._generate_heuristic_sql(query_text, relevant_schemas)
        
        try:
            prompt = self._build_sql_generation_prompt(query_text, relevant_schemas)
            response = self.llm.complete(prompt)
            sql_query = response.text.strip()
            
            # 清理SQL语句
            sql_query = self._extract_sql_from_response(sql_query)
            logging_helper.info_if_verbose(self.logger,self.verbose,f"🤖 LLM生成的SQL: {sql_query}")
            return sql_query
            
        except Exception as e:
            self.logger.warning(f"❌ LLM生成SQL失败: {e}")
            return self._generate_heuristic_sql(query_text, relevant_schemas)

    def _build_sql_generation_prompt(self, query_text: str, relevant_schemas: List[Dict]) -> str:
        """构建SQL生成提示词"""
        
        # 构建相关表结构
        detailed_schemas = "\n相关表的详细结构:\n"
        for schema in relevant_schemas:
            detailed_schemas += f"\n表: {schema['table_name']}\n{schema['content']}\n"
        
        prompt = f"""请基于以下用户查询和相关表结构，生成一个SQLite兼容的SQL查询语句。

        用户查询: "{query_text}"

        相关表结构:
        {detailed_schemas}

        要求:
        1. 只生成SQL语句，不要有其他解释
        2. 确保SQL语法符合SQLite标准
        3. 使用正确的表名和列名
        4. 如果涉及多个表，使用合适的JOIN语句
        5. 如果查询涉及中文，考虑使用LIKE进行模糊匹配

        请直接返回SQL查询语句："""
        
        return prompt

    def _extract_sql_from_response(self, response: str) -> str:
        """从LLM响应中提取SQL语句"""
        # 移除可能的代码块标记
        sql_query = response.replace('```sql', '').replace('```', '').strip()
        
        # 确保以SELECT开头
        if not sql_query.upper().startswith('SELECT'):
            # 尝试找到SELECT语句
            select_match = re.search(r'(SELECT.*?)(?=;|$)', sql_query, re.IGNORECASE | re.DOTALL)
            if select_match:
                sql_query = select_match.group(1).strip()
        
        return sql_query

    def _generate_heuristic_sql(self, query_text: str, relevant_schemas: List[Dict]) -> str:
        """基于启发式规则生成SQL查询"""
        query_lower = query_text.lower()
        
        # 简单的启发式规则
        if any(word in query_lower for word in ['员工', '人员', 'employee']):
            return "SELECT * FROM employees LIMIT 10"
        elif any(word in query_lower for word in ['产品', 'product']):
            return "SELECT * FROM products LIMIT 10"
        elif any(word in query_lower for word in ['商机', 'pipline']):
            return "SELECT * FROM pipline LIMIT 10"
        elif any(word in query_lower for word in ['项目', 'project']):
            return "SELECT * FROM projects LIMIT 10"
        else:
            # 默认查询第一个相关表
            if relevant_schemas:
                table_name = relevant_schemas[0]['table_name']
                return f"SELECT * FROM {table_name} LIMIT 10"
            else:
                return "SELECT * FROM employees LIMIT 5"

    def query(self, query_text: str, show_details: bool = True) -> Dict:
        """执行知识库查询（不涉及数据库）"""
        logging_helper.info_if_verbose(self.logger,show_details,f"📚 开始知识库查询: {query_text}")
        
        try:
            # 1. 检索相关文档
            logging_helper.info_if_verbose(self.logger,show_details,f"🔍 知识库查询步骤1: 检索相关文档...")
            retrieved_nodes = self.retriever.retrieve(query_text)
            
            if show_details:
                logging_helper.info_if_verbose(self.logger,show_details,f"📄 检索到 {len(retrieved_nodes)} 个相关文档片段")
                for i, node in enumerate(retrieved_nodes):
                    logging_helper.info_if_verbose(self.logger,show_details,f"  文档 {i+1}: 相似度 {node.score:.3f}")
                    # 显示文档前100个字符
                    preview = node.text[:100] + "..." if len(node.text) > 100 else node.text
                    logging_helper.info_if_verbose(self.logger,show_details,f"      内容: {preview}")
            
            # 2. 生成答案
            logging_helper.info_if_verbose(self.logger,show_details,f"🤖 知识库查询步骤2: 生成答案...")
            response = self.query_engine.query(query_text)
            final_answer = str(response) if response else "抱歉，没有找到相关信息。"
            
            # 记录生成的答案详情
            logging_helper.info_if_verbose(self.logger,show_details,f"💡 最终答案长度: {len(final_answer)} 字符")
            logging_helper.info_if_verbose(self.logger,show_details,f"📄 最终答案内容: {final_answer}")
            
            # 3. 构建返回结果
            result = {
                "query": query_text,
                "answer": final_answer,
                "source": "knowledge_base",
                "metadata": {
                    "node_count": len(retrieved_nodes),
                    "top_scores": [node.score for node in retrieved_nodes[:3]],
                    "retrieved_nodes": [
                        {
                            "id": node.node_id,
                            "score": node.score,
                            "text_preview": node.text[:200] + "..." if len(node.text) > 200 else node.text
                        }
                        for node in retrieved_nodes[:5]  # 最多返回5个节点的预览
                    ] if show_details else []
                }
            }
            
            logging_helper.info_if_verbose(self.logger,show_details,f"✅ 知识库查询完成")
            return result
            
        except Exception as e:
            self.logger.error(f"❌ 知识库查询失败: {e}")
            return {
                "query": query_text,
                "answer": f"知识库查询失败: {str(e)}",
                "source": "knowledge_base",
                "error": str(e)
            }